#include "Visualisation.h"
#include "Texture.h"
#include "Animation.h"

#include "ComponentManager.h"
#include <iostream>
using namespace std;

#include <math.h>
#include <assert.h>

CVisualisation::CVisualisation(){}
CVisualisation::~CVisualisation()
{
	for(vector<CTexture*>::iterator i=m_vectorTexture.begin(); i<m_vectorTexture.end(); i++)
	{
		delete *i;
	}
	for(vector<CAnimation*>::iterator i=m_vectorAnimation.begin(); i<m_vectorAnimation.end(); i++)
	{
		delete *i;
	}
	for(vector<CTexture*>::iterator i=m_vectorFont.begin(); i<m_vectorFont.end(); i++)
	{
		delete *i;
	}
}


bool CVisualisation::init()
{
	m_screenWidth = 1024;
	m_screenHeight = 789;

	//initialise the video mode
	m_screen=SDL_SetVideoMode(m_screenWidth, m_screenHeight, 32, SDL_HWSURFACE|SDL_DOUBLEBUF);

	if(m_screen == 0)
		return false;
	else 
		return true;
}

bool CVisualisation::loadTexture(int* indexGfx, const string &adrTexture, int spriteWidth, int spriteHeight, 
								 int nbOfSprite, int nbOfSpritePerRow)
{
	CTexture* newTexture = new CTexture();
	if(!newTexture->loadTexture(adrTexture, spriteWidth, spriteHeight, nbOfSprite, nbOfSpritePerRow))
	{
		CM.LOGCONSOLE().Log()<<"LOG : VIS : ERROR : "<<adrTexture<<" can't be loaded.\n";
		CM.LOGCONSOLE().Log()<<"LOG : VIS : SDL ERROR : "<<SDL_GetError()<<".\n";
		return false;
	}
	*indexGfx=m_vectorTexture.size();
	m_vectorTexture.push_back(newTexture);
	return true;
}

bool CVisualisation::loadAnimation(int* indexAnimation, int indexGfx, int indexFirstSprite, int indexLastSprite, 
								   int offsetTime)
{
	//create the animation
	CAnimation* newAnimation = new CAnimation(indexGfx, indexFirstSprite, indexLastSprite, offsetTime);

	//add the animation to the vector
	*indexAnimation=m_vectorAnimation.size();
	m_vectorAnimation.push_back(newAnimation);

	return true;
}

bool CVisualisation::loadFont(int* indexFont, const string& adrTexture, int spriteWidth, int spriteHeight, int nbOfSprite,
		int nbOfSpritePerRow)
{
	CTexture* newTexture = new CTexture();
	if(!newTexture->loadTexture(adrTexture, spriteWidth, spriteHeight, nbOfSprite, nbOfSpritePerRow))
	{
		cout<<"ERROR : "<<adrTexture<<" can't be loaded."<<endl;
		cout<<"SDL ERROR : "<<SDL_GetError()<<endl;
		return false;
	}
	*indexFont=m_vectorFont.size();
	m_vectorFont.push_back(newTexture);
	return true;
}


void CVisualisation::preRender(void)
{
	//create the background color
	Uint32 backgroundColor;
	backgroundColor = SDL_MapRGB(m_screen->format, 255, 0, 0);

	//fill the screen with the background color
	SDL_FillRect(m_screen, 0, backgroundColor);
}

void CVisualisation::postRender(void)
{
	//show the new screen
	SDL_Flip(m_screen);
}

void CVisualisation::displayTexture(int index, const CVector2i& position)
{
	m_vectorTexture[index]->displayTexture(position, m_screen);
}

void CVisualisation::displaySprite(int indexGfx, int indexSprite, const CVector2i& position)
{
	m_vectorTexture[indexGfx]->displaySprite(position, indexSprite, m_screen);
}

bool CVisualisation::displayAnimation(int indexAnimation, const CVector2i& position, int* indexCurrentSprite, 
									  int* timeLastSprite)
{
	//assert
	//assert(indexAnimation>=0);

	bool animationOver=false;
	//if it's the beginning of the animation
	if((*indexCurrentSprite)<=0 || (*indexCurrentSprite)>m_vectorAnimation[indexAnimation]->getIndexLastSprite())
	{
		(*indexCurrentSprite)=m_vectorAnimation[indexAnimation]->getIndexFirstSprite();
	}

	//if a certain amount of time has passed
	if((int)SDL_GetTicks()>=m_vectorAnimation[indexAnimation]->getOffsetTime()+(*timeLastSprite))
	{
		//if it's not the first time that the animation is played
		if((*timeLastSprite)>=0)
		{
			//if it's not the last frame
			if((*indexCurrentSprite)<this->m_vectorAnimation[indexAnimation]->getIndexLastSprite())
			{
				(*indexCurrentSprite)++;
				(*timeLastSprite)=SDL_GetTicks();
			}
			else //if it's the last frame
			{
				(*timeLastSprite)=-1;
			}
		}
		else //if it's the first time that the animation is played
		{
			(*timeLastSprite)=SDL_GetTicks();
		}
	}

	
	displaySprite(m_vectorAnimation[indexAnimation]->getIndexTexture(), (*indexCurrentSprite), position);

	//if it's the last frame	
	if((*indexCurrentSprite)==m_vectorAnimation[indexAnimation]->getIndexLastSprite() && (*timeLastSprite)==-1)
	{
		animationOver=true;
		(*indexCurrentSprite)=-1;
	}
	
	return animationOver;
}

bool CVisualisation::displayCharacter(int indexFont, const CVector2i& position, char character)
{
	const int characterSpace=32;
	if(character!=characterSpace)
	{
		int indexChar;
		if(character>=97 && character<=122)
		{
			indexChar=character-97;
		}
		else
		{
			indexChar=character-65;
		}
		//displayFrame(m_vectorFont[],positionX, positionY, indexChar, transparency);
		m_vectorFont[indexFont]->displaySprite(position, indexChar, m_screen);
	}
	return true;
}

bool CVisualisation::displayText(int indexFont, const CVector2i& position, const string& text)
{
	const int sizeLetter=m_vectorFont[indexFont]->getSpriteWidth();
	for(unsigned int i=0;i<text.size();i++)
	{
		CVector2i offset(i*sizeLetter, 0);
		CVector2i positionLetter;
		positionLetter=position+offset;
		displayCharacter(indexFont, positionLetter, text[i]);
	}
	return true;
}

bool CVisualisation::displayDigit(int indexFont, const CVector2i& position, int digit)
{
	int indexDigit=digit+26;
	//displayFrame(vectorIndexFont[police],positionX, positionY,indexDigit, transparency);
	m_vectorFont[indexFont]->displaySprite(position, indexDigit, m_screen);
	return true;
}

bool CVisualisation::displayNumber(int indexFont, const CVector2i& position, int number)
{
	const int sizeLetter=m_vectorFont[indexFont]->getSpriteWidth();
	int result;
	int numberMax=1000000;
	bool nonZero=false;
	if(number==0)
	{
		CVector2i offset(6*sizeLetter, 0);
		displayDigit(indexFont, position+offset, 0);
	}

	for(int i=0;i<7;i++)
	{
		result=number/numberMax;

		CVector2i offset(i*sizeLetter, 0);
		CVector2i positionDigit;
		positionDigit=position+offset;

		if(result!=0)
		{
			nonZero=true;
		}
		if(nonZero)
		{
			displayDigit(indexFont, positionDigit, result);
			number-=numberMax*result;
		}
		numberMax/=10;
		
	}
	return true;
}

bool CVisualisation::displayCircle(const CVector2i& positionCenter, int radius, int color)
{
	//create an sdl surface of one pixel
	SDL_Surface* pixel = SDL_CreateRGBSurface(SDL_HWSURFACE, 1, 1, 32, 0, 0, 0, 0);

	if(pixel == 0)
		return false;

	//fill the pixel with the given color
	int ret = SDL_FillRect(pixel, 0, color);
	if(ret == -1)
		return false;

	//number of point to draw the circle
	const int circleResolution = 360;

	//for every point
	for(int i=0; i<circleResolution; i++)
	{
		//get its position
		double angle = 360/circleResolution*i;
	
		SDL_Rect sdlPosition;
		sdlPosition.x = (short)(int(radius*cos(angle))+positionCenter.m_x);
		sdlPosition.y = (short)(int(radius*sin(angle))+positionCenter.m_y);
	
		//blit on the screen
		ret = SDL_BlitSurface(pixel, 0, m_screen, &sdlPosition);
		if(ret == -1)
			return false;
	}

	SDL_FreeSurface(pixel);

	return true;
}

bool CVisualisation::displayRectangle(const CVector2i& positionCenter, int width, int height, int color, float rotation)
{

	//get the point creating the rectangle
	CVector2i point[4];
	point[0] = positionCenter + CVector2i(width/2, height/2);
	point[1] = positionCenter + CVector2i(-width/2, height/2);
	point[2] = positionCenter + CVector2i(-width/2, -height/2);
	point[3] = positionCenter + CVector2i(width/2, -height/2);

	//rotate the point using complex numbers : z' - w = (z-w)(cos(a)+isin(a))
	for(int i=0; i<4; i++)
	{
		float x = cos(rotation)*(point[i].m_x-positionCenter.m_x) - sin(rotation)*(point[i].m_y-positionCenter.m_y) + positionCenter.m_x;
		float y = cos(rotation)*(point[i].m_y-positionCenter.m_y) + sin(rotation)*(point[i].m_x-positionCenter.m_x) + positionCenter.m_y;

		point[i].m_x = (int)x;
		point[i].m_y = (int)y;
	}

	
		displayLine(point[1], point[0], color);

		displayLine(point[1], point[2], color);

		displayLine(point[2], point[3], color);

		displayLine(point[3], point[0], color);

	return true;
}

bool CVisualisation::displayLine(const CVector2i& p1, const CVector2i& p2, int color)
{
	int x1 = p1.m_x;
	int y1 = p1.m_y;
	int x2 = p2.m_x;
	int y2 = p2.m_y;
	
	int d, dx, dy, aincr, bincr, xincr, yincr, x, y;

	if (abs(x2 - x1) < abs(y2 - y1)) 
	{
		/* parcours par l'axe vertical */
		if (y1 > y2) 
		{
			std::swap(x1,x2);
			std::swap(y1,y2);
		}

		xincr = x2 > x1 ? 1 : -1;
		dy = y2 - y1;
		dx = abs(x2 - x1);
		d = 2 * dx - dy;
		aincr = 2 * (dx - dy);
		bincr = 2 * dx;
		x = x1;
		y = y1;

		if(x>=0 && x<m_screenWidth && y>=0 && y<m_screenHeight)
			setPixel(x,y,color);

		for (y = y1+1; y <= y2; ++y) 
		{
			if (d >= 0) 
			{
				x += xincr;
				d += aincr;
			} 
			else
				d += bincr;

			if(x>=0 && x<m_screenWidth && y>=0 && y<m_screenHeight)
				setPixel(x,y,color);
		}

	} 
	else 
	{
		/* parcours par l'axe horizontal */
		if (x1 > x2) 
		{
			std::swap(x1,x2);
			std::swap(y1,y2);
		}
		yincr = y2 > y1 ? 1 : -1;
		dx = x2 - x1;
		dy = abs(y2 - y1);
		d = 2 * dy - dx;
		aincr = 2 * (dy - dx);
		bincr = 2 * dy;
		x = x1;
		y = y1;

		if(x>=0 && x<m_screenWidth && y>=0 && y<m_screenHeight)
			setPixel(x,y,color);

		for (x = x1+1; x <= x2; ++x) 
		{
			if (d >= 0) 
			{
				y += yincr;
				d += aincr;
			} 
			else
				d += bincr;

			if(x>=0 && x<m_screenWidth && y>=0 && y<m_screenHeight)
				setPixel(x,y,color);
		} 
	}
	return true;
}

int CVisualisation::getTextureWidth(int indexGfx)const
{
	return m_vectorTexture[indexGfx]->getTextureWidth();
}

int CVisualisation::getTextureHeight(int indexGfx)const
{
	return m_vectorTexture[indexGfx]->getTextureHeight();
}

int CVisualisation::getSpriteWidth(int indexGfx)const
{
	return m_vectorTexture[indexGfx]->getSpriteWidth();
}

int CVisualisation::getSpriteHeight(int indexGfx)const
{
	return m_vectorTexture[indexGfx]->getSpriteHeight();
}

int CVisualisation::getAnimationSpriteWidth(int indexAnim)const
{
	int indexTexture = m_vectorAnimation[indexAnim]->getIndexTexture();
	return getSpriteWidth(indexTexture);
}

int CVisualisation::getAnimationSpriteHeight(int indexAnim)const
{
	int indexTexture = m_vectorAnimation[indexAnim]->getIndexTexture();
	return getSpriteHeight(indexTexture);
}

SDL_Surface* CVisualisation::getScreen()
{
	return m_screen;
}

int CVisualisation::getScreenWidth()
{
	return m_screenWidth;
}

int CVisualisation::getScreenHeight()
{
	return m_screenHeight;
}

void CVisualisation::setPixel(int x, int y, Uint32 color)
{
	assert(x>=0 && x<m_screenWidth && y>=0 && y<m_screenHeight);
	*((Uint32*)(m_screen->pixels)+x+y*m_screen->w)=color;
	return;
}